/*
 * Copyright (C) 2019 Peng fei Pan <panpfpanpf@outlook.me>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.panpf.sketch.zoom;

import me.panpf.sketch.SLog;
import me.panpf.sketch.util.SketchUtils;
import me.panpf.sketch.zoom.scroller.Scroller;
import ohos.agp.components.Image;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

class ScrollBarHelper {

    private ImageZoomer imageZoomer;
    private Paint scrollBarPaint;
    private Context context;

    private int scrollBarSize;
    private int scrollBarMargin;
    private int scrollBarRadius;
    private int scrollBarAlpha = 51;
    private RectF scrollBarRectF = new RectF();
    private RectF tempDisplayRectF = new RectF();

    private EventHandler handler;
    private HiddenScrollBarRunner hiddenScrollBarRunner;
    private FadeScrollBarRunner fadeScrollBarRunner;

    ScrollBarHelper(Context context, ImageZoomer imageZoomer) {
        this.imageZoomer = imageZoomer;
        this.context = context;
        scrollBarPaint = new Paint();
        scrollBarPaint.setColor(new Color(Color.getIntColor("#000000")));
        scrollBarPaint.setAlpha(scrollBarAlpha);
        scrollBarSize = SketchUtils.dp2px(context, 3);
        scrollBarMargin = SketchUtils.dp2px(context, 3);
        scrollBarRadius = Math.round(scrollBarSize / 2f);

        handler = new EventHandler(EventRunner.create(true));
        hiddenScrollBarRunner = new HiddenScrollBarRunner();
        fadeScrollBarRunner = new FadeScrollBarRunner(context);
    }

    void onDraw(Canvas canvas) {
        final RectF drawRectF = tempDisplayRectF;
        imageZoomer.getDrawRect(drawRectF);
        if (drawRectF.isEmpty()) {
            if (SLog.isLoggable(SLog.LEVEL_DEBUG | SLog.TYPE_ZOOM)) {
                SLog.d(ImageZoomer.NAME, "displayRectF is empty. drawScrollBar. drawRectF=%s", drawRectF.toString());
            }
            return;
        }

        Size viewSize = imageZoomer.getViewSize();
        final int viewWidth = viewSize.getWidth();
        final int viewHeight = viewSize.getHeight();
        final float displayWidth = drawRectF.getWidth();
        final float displayHeight = drawRectF.getHeight();

        if (viewWidth <= 0 || viewHeight <= 0 || displayWidth == 0 || displayHeight == 0) {
            if (SLog.isLoggable(SLog.LEVEL_DEBUG | SLog.TYPE_ZOOM)) {
                SLog.d(ImageZoomer.NAME, "size is 0. drawScrollBar. viewSize=%dx%d, displaySize=%sx%s",
                        viewWidth, viewHeight, displayWidth, displayHeight);
            }
            return;
        }

        Image imageView = imageZoomer.getImageView();
        final int finalViewWidth = viewWidth - (scrollBarMargin * 2);
        final int finalViewHeight = viewHeight - (scrollBarMargin * 2);

        if ((int) displayWidth > viewWidth) {
            final float widthScale = (float) viewWidth / displayWidth;
            final int horScrollBarWidth = (int) (finalViewWidth * widthScale);

            RectF horScrollBarRectF = scrollBarRectF;
            horScrollBarRectF.setEmpty();
            horScrollBarRectF.left = imageView.getPaddingLeft() + scrollBarMargin + (drawRectF.left < 0 ? (int) ((Math.abs(drawRectF.left) / drawRectF.width()) * finalViewWidth) : 0);
            horScrollBarRectF.top = imageView.getPaddingTop() + scrollBarMargin + finalViewHeight - scrollBarSize;
            horScrollBarRectF.right = (float) (horScrollBarRectF.left + (double)horScrollBarWidth);
            horScrollBarRectF.bottom = (float) (horScrollBarRectF.top + (double)scrollBarSize);
            canvas.drawRoundRect(horScrollBarRectF, scrollBarRadius, scrollBarRadius, scrollBarPaint);
        }

        if ((int) displayHeight > viewHeight) {
            final float heightScale = (float) viewHeight / displayHeight;
            final int verScrollBarHeight = (int) (finalViewHeight * heightScale);

            RectF verScrollBarRectF = scrollBarRectF;
            verScrollBarRectF.setEmpty();
            verScrollBarRectF.left = imageView.getPaddingLeft() + scrollBarMargin + finalViewWidth - scrollBarSize;
            verScrollBarRectF.top = imageView.getPaddingTop() + scrollBarMargin + (drawRectF.top < 0 ? (int) ((Math.abs(drawRectF.top) / drawRectF.height()) * finalViewHeight) : 0);
            verScrollBarRectF.right = (float) ((double)verScrollBarRectF.left + scrollBarSize);
            verScrollBarRectF.bottom = (float) ((double)verScrollBarRectF.top + verScrollBarHeight);
            canvas.drawRoundRect(verScrollBarRectF, scrollBarRadius, scrollBarRadius, scrollBarPaint);
        }
    }

    /**
     * 此方法里没有执行 imageView.invalidate()，因为回调的地方会有执行
     */
    void onMatrixChanged() {
        scrollBarPaint.setAlpha(scrollBarAlpha);

        if (fadeScrollBarRunner.isRunning()) {
            fadeScrollBarRunner.abort();
        }
        handler.removeTask(hiddenScrollBarRunner);

        handler.postTask(hiddenScrollBarRunner, 800);
    }

    private void invalidateView() {
        context.getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                Image imageView = imageZoomer.getImageView();
                if (imageView != null) {
                    imageView.invalidate();
                }
            }
        });
    }

    private class HiddenScrollBarRunner implements Runnable {

        @Override
        public void run() {
            fadeScrollBarRunner.start();
        }
    }

    private class FadeScrollBarRunner implements Runnable {
        private Scroller scroller;

        FadeScrollBarRunner(Context context) {
            this.scroller = new Scroller(context);
            scroller.forceFinished(true);
        }

        public void start() {
            scroller.startScroll(scrollBarAlpha, 0, -scrollBarAlpha, 0);
            handler.postTask(this);
        }

        boolean isRunning() {
            return !scroller.isFinished();
        }

        void abort() {
            scroller.forceFinished(true);
        }

        @Override
        public void run() {
            if (scroller.computeScrollOffset()) {
                scrollBarPaint.setAlpha(scroller.getCurrX());
                invalidateView();
                handler.postTask(this, 60);
            }
        }
    }
}
